package com.huaweicloud.servicestage.plugin;

/* 导入依赖模块 */
// 日志打印

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.beust.jcommander.JCommander;
import com.huaweicloud.sdk.core.auth.BasicCredentials;
import com.huaweicloud.sdk.core.exception.ServiceResponseException;
import com.huaweicloud.sdk.core.http.HttpConfig;
import com.huaweicloud.sdk.servicestage.v2.ServiceStageClient;
import com.huaweicloud.sdk.servicestage.v2.model.ApplicationView;
import com.huaweicloud.sdk.servicestage.v2.model.ChangeComponentRequest;
import com.huaweicloud.sdk.servicestage.v2.model.ChangeComponentResponse;
import com.huaweicloud.sdk.servicestage.v2.model.ChangeInstanceRequest;
import com.huaweicloud.sdk.servicestage.v2.model.ChangeInstanceResponse;
import com.huaweicloud.sdk.servicestage.v2.model.ComponentModify;
import com.huaweicloud.sdk.servicestage.v2.model.ComponentView;
import com.huaweicloud.sdk.servicestage.v2.model.InstanceListView;
import com.huaweicloud.sdk.servicestage.v2.model.InstanceModify;
import com.huaweicloud.sdk.servicestage.v2.model.ListApplicationsRequest;
import com.huaweicloud.sdk.servicestage.v2.model.ListApplicationsResponse;
import com.huaweicloud.sdk.servicestage.v2.model.ListComponentsRequest;
import com.huaweicloud.sdk.servicestage.v2.model.ListComponentsResponse;
import com.huaweicloud.sdk.servicestage.v2.model.ListInstancesRequest;
import com.huaweicloud.sdk.servicestage.v2.model.ListInstancesResponse;
import com.huaweicloud.sdk.servicestage.v2.model.ShowInstanceDetailRequest;
import com.huaweicloud.sdk.servicestage.v2.model.ShowInstanceDetailResponse;
import com.huaweicloud.sdk.servicestage.v2.model.SourceKind;
import com.huaweicloud.sdk.servicestage.v2.model.SourceObject;
import com.huaweicloud.sdk.servicestage.v2.model.SourceOrArtifact.StorageEnum;
import com.huaweicloud.sdk.servicestage.v2.model.SourceOrArtifact.TypeEnum;
import com.huaweicloud.servicestage.command.Command;
import com.huaweicloud.servicestage.command.CommandAction;
import com.huaweicloud.servicestage.command.CommandInit;
import com.huaweicloud.servicestage.command.CommandList;
import com.huaweicloud.servicestage.command.CommandUgrade;
import com.huaweicloud.servicestage.utils.CsvUtils;

public class Application {

    public static final String SS_CONFIG = ".ss.config";

    public static String changeComponent(ServiceStageClient client, InstanceVisitor visitor,
        ComponentModify componentModify) {
        try {
            ChangeComponentRequest request = new ChangeComponentRequest()
                .withApplicationId(visitor.getApplicationId())
                .withComponentId(visitor.getComponentId())
                .withBody(componentModify);
            ChangeComponentResponse response = client.changeComponent(request);
            return response.getName();
        } catch (ServiceResponseException e) {
            System.out.println("HttpStatusCode: " + e.getHttpStatusCode());
            System.out.println("RequestId: " + e.getRequestId());
            System.out.println("ErrorCode: " + e.getErrorCode());
            System.out.println("ErrorMsg: " + e.getErrorMsg());
            return null;
        }
    }

    private static ComponentModify generateComponentModify(String region, String packageUrl, String bucketName) {
        ObsArtifact obsArtifact = new ObsArtifact();
        obsArtifact.withStorage(StorageEnum.OBS)
            .withType(TypeEnum.PACKAGE)
            .withAuth("iam")
            .withUrl(packageUrl);
        if (packageUrl.startsWith("obs://")) {
            Map<String, String> properties = new HashMap<>();
            properties.put("endpoint", "https://obs." + region + ".myhuaweicloud.com");
            properties.put("bucket", bucketName);
            obsArtifact.setProperties(properties);
        }
        SourceObject sourceObject = new SourceObject()
            .withKind(SourceKind.ARTIFACT)
            .withSpec(obsArtifact);
        ComponentModify componentModify = new ComponentModify()
            .withSource(sourceObject);
        return componentModify;
    }

    public static String updateInstance(ServiceStageClient client, InstanceVisitor visitor, String componentName,
        String oldVersion) {
        try {
            String[] versionArray = oldVersion.split("\\.");
            if (versionArray.length != 3) {
                return null;
            }
            versionArray[2] = String.valueOf(Integer.parseInt(versionArray[2]) + 1);
            String newVersion = String.join(".", versionArray);

            Map<String, String> artifactProperty = new HashMap<>();
            artifactProperty.put("storage", "swr");
            artifactProperty.put("type", "image");
            artifactProperty.put("auth", "iam");
            artifactProperty.put("url", componentName + ":v${index}");
            Map<String, Object> artifacts = new HashMap<>();

            artifacts.put(componentName, artifactProperty);
            InstanceModify instanceModify = new InstanceModify()
                .withVersion(newVersion)
                .withArtifacts(artifacts);
            ChangeInstanceRequest request = new ChangeInstanceRequest()
                .withApplicationId(visitor.getApplicationId())
                .withComponentId(visitor.getComponentId())
                .withInstanceId(visitor.getInstanceId())
                .withBody(instanceModify);
            ChangeInstanceResponse response = client.changeInstance(request);
            return response.getJobId();
        } catch (ServiceResponseException e) {
            System.out.println("HttpStatusCode: " + e.getHttpStatusCode());
            System.out.println("RequestId: " + e.getRequestId());
            System.out.println("ErrorCode: " + e.getErrorCode());
            System.out.println("ErrorMsg: " + e.getErrorMsg());
            return null;
        }
    }

    public static String getInstanceVersion(ServiceStageClient client,
        InstanceVisitor visitor) {
        try {
            ShowInstanceDetailRequest request = new ShowInstanceDetailRequest()
                .withApplicationId(visitor.getApplicationId())
                .withComponentId(visitor.getComponentId())
                .withInstanceId(visitor.getInstanceId());
            ShowInstanceDetailResponse response = client.showInstanceDetail(request);
            return response.getVersion();
        } catch (ServiceResponseException e) {
            System.out.println("HttpStatusCode: " + e.getHttpStatusCode());
            System.out.println("RequestId: " + e.getRequestId());
            System.out.println("ErrorCode: " + e.getErrorCode());
            System.out.println("ErrorMsg: " + e.getErrorMsg());
            return null;
        }
    }

    public static List<ApplicationView> listApplications(ServiceStageClient client, String applicationId) {
        try {
            ListApplicationsRequest request = new ListApplicationsRequest();
            ListApplicationsResponse response = client.listApplications(request);
            if (applicationId == null) {
                return response.getApplications();
            }
            return response.getApplications().stream().filter(app -> app.getId().equals(applicationId))
                .collect(Collectors.toList());
        } catch (ServiceResponseException e) {
            System.out.println("HttpStatusCode: " + e.getHttpStatusCode());
            System.out.println("RequestId: " + e.getRequestId());
            System.out.println("ErrorCode: " + e.getErrorCode());
            System.out.println("ErrorMsg: " + e.getErrorMsg());
            return null;
        }
    }

    public static List<ComponentView> listComponents(ServiceStageClient client, String applicationId) {
        try {
            ListComponentsRequest request = new ListComponentsRequest()
                .withApplicationId(applicationId);
            ListComponentsResponse response = client.listComponents(request);
            return response.getComponents();
        } catch (ServiceResponseException e) {
            System.out.println("HttpStatusCode: " + e.getHttpStatusCode());
            System.out.println("RequestId: " + e.getRequestId());
            System.out.println("ErrorCode: " + e.getErrorCode());
            System.out.println("ErrorMsg: " + e.getErrorMsg());
            return null;
        }
    }

    public static List<InstanceListView> listInstances(ServiceStageClient client, String applicationId,
        String componentId) {
        try {
            ListInstancesRequest request = new ListInstancesRequest()
                .withApplicationId(applicationId)
                .withComponentId(componentId);
            ListInstancesResponse response = client.listInstances(request);
            return response.getInstances();
        } catch (ServiceResponseException e) {
            System.out.println("HttpStatusCode: " + e.getHttpStatusCode());
            System.out.println("RequestId: " + e.getRequestId());
            System.out.println("ErrorCode: " + e.getErrorCode());
            System.out.println("ErrorMsg: " + e.getErrorMsg());
            return null;
        }
    }

    public static void executeInitCommand(CommandInit commandInit) {
        String usrHome = System.getProperty("user.home");
        File initFile = new File(usrHome + File.separator + SS_CONFIG);
        try (BufferedWriter bufferedWriter = new BufferedWriter(
            new OutputStreamWriter(new FileOutputStream(initFile, false),
                StandardCharsets.UTF_8))) {
            bufferedWriter.write("access_key=" + commandInit.getAccessKey() + "\n");
            bufferedWriter.write("secret_key=" + commandInit.getSecretKey());
            System.out.println("Init successfully");
        } catch (IOException exception) {
            System.out.println(exception.getMessage());
        }
    }

    public static void executeListCommand(CommandList commandList) {
        CommandInit commandInit = parseConfigFile();
        if (commandInit.getSecretKey() == null || commandInit.getAccessKey() == null) {
            System.out.println("Access key or secret key is missing. Please init first");
            System.exit(1);
        }

        String endpoint = "https://servicestage." + commandList.getRegion() + ".myhuaweicloud.com";
        String projectId = IamProject.qureyProjectId(commandInit, commandList.getRegion());
        if (projectId == null) {
            System.out.println("Fail to get user project id");
            System.exit(1);
        }

        // 配置客户端属性
        HttpConfig config = HttpConfig.getDefaultHttpConfig();
        config.withIgnoreSSLVerification(true);

        // 创建认证
        BasicCredentials auth = new BasicCredentials()
            .withAk(commandInit.getAccessKey())
            .withSk(commandInit.getSecretKey())
            .withProjectId(projectId);

        // 创建servicestageClient实例并初始化
        ServiceStageClient servicestageClient = ServiceStageClient.newBuilder()
            .withHttpConfig(config)
            .withCredential(auth)
            .withEndpoint(endpoint)
            .build();

        List<ApplicationView> applications = listApplications(servicestageClient, commandList.getApplicationId());
        if (applications == null) {
            return;
        }

        List<String> records = new ArrayList<>();
        for (ApplicationView app : applications) {
            List<ComponentView> components = listComponents(servicestageClient, app.getId());
            if (components == null) {
                continue;
            }
            for (ComponentView component : components) {
                List<InstanceListView> instances = listInstances(servicestageClient, app.getId(), component.getId());
                for (InstanceListView instance : instances) {
                    records.add(
                        app.getName() + "," + component.getName() + "," + instance.getName() + "," + app.getId() + ","
                            + component.getId() + "," + instance.getId());
                }
            }
        }
        CsvUtils.writeInstancesCsv(records);
    }

    public static void executeUpgradeCommand(CommandUgrade commandUgrade) {
        CommandInit commandInit = parseConfigFile();
        if (commandInit.getSecretKey() == null || commandInit.getAccessKey() == null) {
            System.out.println("Access key or secret key is missing. Please init first");
            System.exit(1);
        }
        String region = commandUgrade.getRegion();
        String endpoint = "https://servicestage." + region + ".myhuaweicloud.com";
        String packageUrl = commandUgrade.getPackageUrl();
        String bucketName = null;
        InstanceVisitor visitor = new InstanceVisitor(commandUgrade.getApplicationId(),
            commandUgrade.getComponentId(), commandUgrade.getInstanceId());

        String projectId = IamProject.qureyProjectId(commandInit, region);
        if (projectId == null) {
            System.out.println("Fail to get user project id");
            System.exit(1);
        }

        if (!packageUrl.startsWith("obs://")) {
            return;
        }

        String[] packageUrlArray = packageUrl.replace("obs://", "").split("/");
        if (packageUrlArray.length < 2) {
            System.out.println("invalid package url");
            return;
        }
        bucketName = packageUrlArray[0];

        // 配置客户端属性
        HttpConfig config = HttpConfig.getDefaultHttpConfig();
        config.withIgnoreSSLVerification(true);

        // 创建认证
        BasicCredentials auth = new BasicCredentials()
            .withAk(commandInit.getAccessKey())
            .withSk(commandInit.getSecretKey())
            .withProjectId(projectId);

        // 创建servicestageClient实例并初始化
        ServiceStageClient servicestageClient = ServiceStageClient.newBuilder()
            .withHttpConfig(config)
            .withCredential(auth)
            .withEndpoint(endpoint)
            .build();

        String instanceVersion = getInstanceVersion(servicestageClient, visitor);
        if (instanceVersion == null) {
            return;
        }

        ComponentModify componentModify = generateComponentModify(region, packageUrl, bucketName);
        String componentName = changeComponent(servicestageClient, visitor, componentModify);
        if (componentName == null) {
            return;
        }

        String jobId = updateInstance(servicestageClient, visitor, componentName, instanceVersion);
        if (jobId != null) {
            System.out.println("Servicestage task is submitted successfully");
        }

    }

    private static CommandInit parseConfigFile() {
        CommandInit commandInit = new CommandInit();
        String usrHome = System.getProperty("user.home");
        File initFile = new File(usrHome + File.separator + SS_CONFIG);
        try (BufferedReader bufferedReader = new BufferedReader(new FileReader(initFile))) {
            String str;
            while ((str = bufferedReader.readLine()) != null) {
                String[] configArray = str.split("=");
                if (configArray.length != 2) {
                    continue;
                }
                if (configArray[0].trim().equals("access_key")) {
                    commandInit.setAccessKey(configArray[1].trim());
                } else if (configArray[0].trim().equals("secret_key")) {
                    commandInit.setSecretKey(configArray[1].trim());
                }
            }
        } catch (IOException exception) {
            System.out.println(exception.getMessage());
        }
        return commandInit;
    }

    public static void main(String[] args) {
        JCommander jc = Command.initCommand(args);
        if (jc.getParsedCommand() == null) {
            jc.usage();
            System.exit(1);
        }
        if (jc.getParsedCommand().equals(CommandAction.UPGRADE)) {
            CommandUgrade commandUgrade = (CommandUgrade) jc.getCommands().get(CommandAction.UPGRADE).getObjects()
                .get(0);
            executeUpgradeCommand(commandUgrade);
        } else if (jc.getParsedCommand().equals(CommandAction.INIT)) {
            CommandInit commandInit = (CommandInit) jc.getCommands().get(CommandAction.INIT).getObjects().get(0);
            executeInitCommand(commandInit);
        } else if (jc.getParsedCommand().equals(CommandAction.LIST)) {
            CommandList commandList = (CommandList) jc.getCommands().get(CommandAction.LIST).getObjects().get(0);
            executeListCommand(commandList);
        }
    }
}